using System;
using System.Collections;
using System.Data;
using System.Windows.Forms;

namespace sforceExplorer
{
	/// <summary>
	/// Summary description for Common.
	/// </summary>
	public class Utility
	{
		public Utility()
		{
			//
			// TODO: Add constructor logic here
			//
		}
		
		static SforceServiceWrapper _binding = new SforceServiceWrapper();
		static sforce.LoginResult _loginResult = null;
		static dbRepConfigBean _RepConfig = new dbRepConfigBean();

		public static dbRepConfigBean RepConfig 
		{
			get { return _RepConfig; }
			set { _RepConfig = value; }
		}
		public static sforce.LoginResult loginResult 
		{
			get { return _loginResult; }
			set { _loginResult = value; }
		}

		public static SforceServiceWrapper binding 
		{
		get { return _binding; }
		set { _binding = value; }
		}

		
//		public static string GetFieldValue(string fieldName, System.Xml.XmlElement[] any) 
//		{
//			for (int i=0;i<any.Length;i++) 
//			{
//				if (any[i].LocalName.ToLower().Equals(fieldName.ToLower()))
//				return any[i].InnerText;
//			}
//		return null;
//		}

		public static System.Data.DataTable CreateDataTable(string objectName, sforce.DescribeSObjectResult dsr) 
		{
			System.Data.DataTable dt = new System.Data.DataTable(objectName);
			//build column list
			string selectList = "";
			for (int i=0;i<dsr.fields.Length;i++) 
			{
				System.Data.DataColumn dc = new System.Data.DataColumn(dsr.fields[i].name, GetSystemType(dsr.fields[i].type));
				dc.ReadOnly = !dsr.fields[i].updateable;
				dc.AllowDBNull = dsr.fields[i].nillable;
				if (dsr.fields[i].length > 0)
					if (dsr.fields[i].type == sforce.fieldType.picklist)
						dc.MaxLength = 255;
					else
						dc.MaxLength = dsr.fields[i].length;
				if (dsr.fields[i].label != null)
					dc.Caption = dsr.fields[i].label;
				else
					dc.Caption = dsr.fields[i].name;
				if (dsr.fields[i].type.Equals(sforce.fieldType.reference) || dsr.fields[i].type.Equals(sforce.fieldType.id))
					dc.ExtendedProperties.Add("referenceTo", true);
				else
					dc.ExtendedProperties.Add("referenceTo", false);
				dt.Columns.Add(dc);
				selectList += dsr.fields[i].name + ", ";
			}
			return dt;
		}

		public static ArrayList ConvertQueryResultsToHashtable(sforce.QueryResult qr) 
		{
			ArrayList outArray = new ArrayList();
			for (int i=0;i<qr.records.Length;i++) 
			{
				Hashtable ht = new Hashtable();
				for (int j=0;j<qr.records[i].Any.Length;j++) 
				{
					string fieldName = qr.records[i].Any[j].LocalName;
					string fieldValue = qr.records[i].Any[j].InnerText;
					if (!ht.ContainsKey(fieldName.ToLower()))
					{
						if (fieldValue == null || fieldValue.Length == 0)
							ht.Add(fieldName.ToLower(), System.DBNull.Value);
						else
							ht.Add(fieldName.ToLower(), ConvertXmlToType(fieldValue, GetFieldType(qr.records[i].type, fieldName)));
					}
				}
				outArray.Add(ht);
			}
			return outArray;
		}
		public static ArrayList ConvertRetrieveResultsToHashtable(sforce.sObject[] records) 
		{
			ArrayList outArray = new ArrayList();
			for (int i=0;i<records.Length;i++) 
			{
				Hashtable ht = new Hashtable();
				for (int j=0;j<records[i].Any.Length;j++) 
				{
					string fieldName = records[i].Any[j].LocalName;
					string fieldValue = records[i].Any[j].InnerText;
					if (!ht.ContainsKey(fieldName.ToLower()))
					{
						if (fieldValue == null || fieldValue.Length == 0)
							ht.Add(fieldName.ToLower(), System.DBNull.Value);
						else
							ht.Add(fieldName.ToLower(), Utility.ConvertXmlToType(fieldValue, Utility.GetFieldType(records[i].type, fieldName)));
					}
				}
				outArray.Add(ht);
			}
			return outArray;
		}
		public static string CreateSelectList(sforce.DescribeSObjectResult dsr) 
		{
			string selectList = "";
			for (int i=0;i<dsr.fields.Length;i++) 
			{
				selectList += dsr.fields[i].name + ", ";
			}
			selectList = selectList.Substring(0, selectList.Length - 2);
			return selectList;
		}

		public static string FormatISO861(System.DateTime dt) 
		{
			return System.Xml.XmlConvert.ToString(dt);
		}

		public static sforce.sObject[] RowsToObjects(System.Data.DataSet ds) 
		{
			try 
			{
				System.Collections.ArrayList flds = new System.Collections.ArrayList();
				System.Xml.XmlDocument xdoc = new System.Xml.XmlDocument();
				//sforce.sObject[] records = new sforce.sObject[ds.Tables[0].Rows.Count];
				ArrayList records = new ArrayList();
				for (int k=0;k<ds.Tables.Count;k++) 
				{
					if (ds.Tables[k].Rows.Count > 0) 
					{
						for (int i=0;i<ds.Tables[0].Rows.Count;i++) 
						{
							sforce.sObject record = new sforce.sObject();
							record.type = ds.Tables[0].TableName;
							for (int j=0;j<ds.Tables[0].Columns.Count;j++) 
							{
								if (!ds.Tables[0].Columns[j].ReadOnly) 
								{
									if (ds.Tables[0].Rows[i][ds.Tables[0].Columns[j].ColumnName] != null && ds.Tables[0].Rows[i][ds.Tables[0].Columns[j].ColumnName] !=  DBNull.Value) 
									{
										System.Xml.XmlElement xEl = xdoc.CreateElement(ds.Tables[0].Columns[j].ColumnName);
										if (ds.Tables[0].Columns[j].DataType == typeof(System.DateTime))
											xEl.InnerText = FormatISO861((DateTime) ds.Tables[0].Rows[i][ds.Tables[0].Columns[j].ColumnName]);
										else
											xEl.InnerText = ds.Tables[0].Rows[i][ds.Tables[0].Columns[j].ColumnName].ToString();
										flds.Add(xEl);
									} 
								}
								else if (ds.Tables[0].Columns[j].ColumnName.Equals("Id")) 
								{
									record.Id = ds.Tables[0].Rows[i][ds.Tables[0].Columns[j].ColumnName].ToString();
								}
							}
							System.Xml.XmlElement[] xarray = new System.Xml.XmlElement[flds.Count];
							flds.CopyTo(xarray);
							record.Any = xarray;
							records.Add(record);
							//records[i] = record;
						}
					}
				}
				return (sforce.sObject[])records.ToArray(typeof(sforce.sObject));
			}
			catch (Exception ex) 
			{
				System.Diagnostics.Trace.WriteLine(ex.Message);
				return null;
			}
		}

		public static void LoadDataTable(sforce.QueryResult qr, System.Data.DataTable dt) 
		{
			dt.Rows.Clear();
			bool keepLooping = true;
			while (keepLooping) 
			{
				sforce.sObject[] records =  qr.records;
				for (int i=0;i<records.Length;i++) 
				{
					System.Data.DataRow dr = dt.NewRow();
					if (records[i].Id != null) 
						dr["Id"] = records[i].Id;
					System.Xml.XmlElement[] fields = records[i].Any;
					for (int j=0;j<fields.Length;j++) 
					{
						if (!fields[j].LocalName.Equals("type"))
						{
							if (fields[j].InnerText.Length > 0)
								dr[fields[j].LocalName] = fields[j].InnerText;
							else if (!dr.Table.Columns[fields[j].LocalName].AllowDBNull) 
							{
								if (dr.Table.Columns[fields[j].LocalName].DataType.Equals(typeof(System.DateTime)))
									dr[fields[j].LocalName] = System.DateTime.Now;
								else if (dr.Table.Columns[fields[j].LocalName].DataType.Equals(typeof(System.Double)))
									dr[fields[j].LocalName] = 0.0;
								else if (dr.Table.Columns[fields[j].LocalName].DataType.Equals(typeof(System.Int32)))
									dr[fields[j].LocalName] = 0;
								else
									dr[fields[j].LocalName] = "(missing)";
							}
						}

					}
					dt.Rows.Add(dr);
				}
				if (!qr.done) 
				{
					qr = Utility.binding.queryMore(qr.queryLocator);
				} 
				else 
				{
					keepLooping = false;
				}
			}
		}

		public static void CreateDataGridGridTableStyle(System.Windows.Forms.DataGrid grid)
		{
			CurrencyManager myCurrencyManager;
			DataGridTableStyle myGridTableStyle;
			myCurrencyManager = (CurrencyManager)grid.FindForm().BindingContext[(DataSet)grid.DataSource, grid.DataMember];
			myGridTableStyle = new DataGridTableStyle(myCurrencyManager);
			// Add the table style to the collection of a DataGrid.
			myGridTableStyle.GridColumnStyles.Clear();
			//dataGrid1.TableStyles.Add(myGridTableStyle);
			System.Data.DataTable dt = ((DataSet)grid.DataSource).Tables[0];
			for (int i=0;i<dt.Columns.Count;i++) 
			{
				if ((bool)dt.Columns[i].ExtendedProperties["referenceTo"])
				{
					DataGridHyperLinkColumn dhc = new DataGridHyperLinkColumn();
					dhc.LinkLabelColumnClick+=new sforceExplorer.DataGridHyperLinkColumn.LinkLabelColumnClickDelegate(dhc_LinkLabelColumnClick);
					dhc.MappingName = dt.Columns[i].ColumnName;
					dhc.HeaderText = dt.Columns[i].ColumnName;
					myGridTableStyle.GridColumnStyles.Add((DataGridColumnStyle)dhc);
				} 
				else if (dt.Columns[i].DataType.Equals(typeof(System.Boolean))) 
				{
					int x = myGridTableStyle.GridColumnStyles.Add(new DataGridBoolColumn());
					string mname = dt.Columns[i].ColumnName;
					myGridTableStyle.GridColumnStyles[x].MappingName = mname;
					myGridTableStyle.GridColumnStyles[x].HeaderText = mname;
				} 
				else 
				{
					int x = myGridTableStyle.GridColumnStyles.Add(new DataGridTextBoxColumn());
					string mname = dt.Columns[i].ColumnName;
					myGridTableStyle.GridColumnStyles[x].MappingName = mname;
					myGridTableStyle.GridColumnStyles[x].HeaderText = mname;
				}
			}
			grid.TableStyles.Clear();
			grid.TableStyles.Add(myGridTableStyle);
			grid.Tag = Utility.binding.describeSObject(dt.TableName).urlDetail;
		}
		private static void dhc_LinkLabelColumnClick(object sender, LinkLabelColumnEventArgs e)
		{
			if (e.Id != null && e.Id != "") 
			{
				string frontDoor = Utility.binding.Url.Replace("-api", "");
				frontDoor = frontDoor.Substring(0, frontDoor.IndexOf("force.com") + 10);
				frontDoor += "secur/frontdoor.jsp?sid=" + Utility.binding.SessionHeaderValue.sessionId + "&retURL=";
				frontDoor += "/" + (string)e.Id;
				System.Diagnostics.Process.Start(frontDoor);
			}
		}

		
		#region Describe related caching calls
		public static ArrayList GetObjectTypes() 
		{
			if (!DataCache.Cache.ContainsKey("objecttypes"))
				DataCache.Cache.Add("objecttypes", new ArrayList(Utility.binding.describeGlobal().types));
			return (ArrayList)DataCache.Cache["objecttypes"];
		}

		//The describe cache is structured like:
		//	type			(Hashtable)
		//		describe	(sforce.describeSObjectResult)
		//		fields		(Hashtable)
		public static Hashtable GetDescribe(string sobjectType) 
		{
			if (!DataCache.Cache.ContainsKey(sobjectType.ToLower()))
				Utility.binding.describeSObject(sobjectType);
			return (Hashtable)DataCache.Cache[sobjectType.ToLower()];
		}
		public static Hashtable GetFields(string objectType) 
		{
			return (Hashtable)GetDescribe(objectType)["fields"];
		}
		public static sforce.Field GetField(string sobjectType, string fieldName) 
		{
			return (sforce.Field)GetFields(sobjectType)[fieldName.ToLower()];
		}
		public static System.Type GetFieldType(string sobjectType, string fieldName) 
		{
			return GetSystemType(GetField(sobjectType, fieldName).type);
		}
		public static bool FieldIsNullable(string sobjectType, string fieldName) 
		{
			return GetField(sobjectType, fieldName).nillable;
		}
		public static bool TableIsReplicateable(string sobjectType) 
		{
			return Utility.binding.describeSObject(sobjectType).replicateable;
		}
		public static sforce.PicklistEntry[] GetPickList(string sobjectType, string fieldName) 
		{
			return GetField(sobjectType, fieldName).picklistValues;
		}

		#endregion
		
		public static object ConvertXmlToType(string val, System.Type type) 
		{
			object returnVal = null;
			switch (type.ToString()) {
				case "System.DateTime":
					returnVal = System.Xml.XmlConvert.ToDateTime(val);
					break;
				case "System.Int16":
					returnVal = System.Xml.XmlConvert.ToInt16(val);
					break;
				case "System.Int32":
					returnVal = System.Xml.XmlConvert.ToInt32(val);
					break;
				case "System.Int64":
					returnVal = System.Xml.XmlConvert.ToInt64(val);
					break;
				case "System.Boolean":
					returnVal = System.Xml.XmlConvert.ToBoolean(val);
					break;
				default:
					returnVal = val;
					break;
			}
			return returnVal;
		}
		public static System.Type GetSystemType(sforce.fieldType sfdcType) 
		{
			System.Type returnValue = System.Type.GetType("System,String");

			switch (sfdcType) 
			{
				case sforce.fieldType.@string:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.picklist:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.combobox:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.reference:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.base64:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.boolean:
					returnValue = System.Type.GetType("System.Boolean");
					break;
				case sforce.fieldType.currency:
					returnValue = System.Type.GetType("System.Double");
					break;
				case sforce.fieldType.textarea:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.@int:
					returnValue = System.Type.GetType("System.Int32");
					break;
				case sforce.fieldType.@double:
					returnValue = System.Type.GetType("System.Double");
					break;
				case sforce.fieldType.percent:
					returnValue = System.Type.GetType("System.Int32");
					break;
				case sforce.fieldType.phone:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.id:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.date:
					returnValue = System.Type.GetType("System.DateTime");
					break;
				case sforce.fieldType.datetime:
					returnValue = System.Type.GetType("System.DateTime");
					break;
				case sforce.fieldType.url:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.email:
					returnValue = System.Type.GetType("System.String");
					break;
				case sforce.fieldType.multipicklist:
					returnValue = System.Type.GetType("System.String");
					break;
			}
			return returnValue;
		}

		public static string ConvertArrayToString(string[] fields) 
		{
			string returnVal = "";
			bool idFound = false;
			for (int i=0;i<fields.Length;i++) 
			{
				if (fields[i].ToLower().Equals("id"))
					idFound = true;
				returnVal += fields[i] + ", ";
			}
			if (!idFound)
				returnVal += "Id";
			else
				returnVal = returnVal.Substring(0, returnVal.Length - 2);
			return returnVal;
		}
	}
}
